package com.uuah.server.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.UuahServer;
import com.uuah.server.api.endpoint.IEndpointURI;
import com.uuah.server.api.transport.IConnector;
import com.uuah.server.config.registry.ServiceDescriptorFactory;
import com.uuah.server.transport.service.TransportFactory;
import com.uuah.utils.IOUtils;
import com.uuah.utils.StringUtils;

public final class UuahServerUtils {
	private static final Logger logger = LoggerFactory
			.getLogger(UuahServerUtils.class);
	public static final String SEPARATOR = ".";
	public static final String CONNECTOR_PREFIX = "connector";
	public static final String ENDPOINT_PREFIX = "endpoint";

	public static String getEndpointName(final IEndpointURI endpointUri) {
		String address = endpointUri.getAddress();
		if (StringUtils.isBlank(address)) {
			address = endpointUri.toString();
		}
		address = (address.indexOf(":/") > -1 ? address : endpointUri
				.getScheme()
				+ SEPARATOR + address);
		String name = ENDPOINT_PREFIX + SEPARATOR
				+ replaceObjectNameChars(address);

		return ensureUniqueEndpoint(name);
	}

	protected static String ensureUniqueEndpoint(String name) {
		int i = 0;
		String tempName = name;

		while (UuahServer.getUuahContext().getRegistry().lookupObject(tempName) != null) {
			i++;
			tempName = name + SEPARATOR + i;
		}
		return tempName;
	}

	protected static String ensureUniqueConnector(String name) {
		int i = 0;
		String tempName = name;

		try {
			while (UuahServer.getUuahContext().getRegistry().lookupConnector(
					tempName) != null) {
				i++;
				tempName = name + SEPARATOR + i;
			}
		} catch (Exception e) {
			// ignore
		}
		return tempName;
	}

	public static String getConnectorName(IConnector connector) {
		if (connector.getName() != null
				&& connector.getName().indexOf('#') == -1) {
			String name = replaceObjectNameChars(connector.getName());
			return ensureUniqueConnector(name);
		} else {
			int i = 0;
			String name = CONNECTOR_PREFIX + SEPARATOR
					+ connector.getProtocol() + SEPARATOR + i;
			return ensureUniqueConnector(name);
		}
	}

	public static String replaceObjectNameChars(String name) {
		String value = name.replaceAll("//", SEPARATOR);
		value = value.replaceAll("\\p{Punct}", SEPARATOR);
		value = value.replaceAll("\\" + SEPARATOR + "{2,}", SEPARATOR);
		if (value.endsWith(SEPARATOR)) {
			value = value.substring(0, value.length() - 1);
		}
		return value;
	}

	public static final String SERVICE_ROOT = "META-INF/services/";
	public static final String PROVIDER_SERVICE_PATH = "com/uuah/providers/";
	public static final String EXCEPTION_SERVICE_PATH = "com/uuah/config/";

	public static Properties findServiceDescriptor(String type, String name) {
		if (type.equals(ServiceDescriptorFactory.PROVIDER_SERVICE_TYPE)) {
			return findServiceDescriptor(PROVIDER_SERVICE_PATH, name,
					TransportFactory.class);
		} else {
			logger.warn("Attempt to lookup unrecognized service type: " + type);
			return null;
		}

	}

	public static Properties findServiceDescriptor(String path, String name,
			Class currentClass) {
		if (!name.endsWith(".properties")) {
			name += ".properties";
		}

		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		if (!path.endsWith("/")) {
			path += "/";
		}
		if (path.startsWith(SERVICE_ROOT)) {
			path += name;
		} else {
			path = SERVICE_ROOT + path + name;
		}
		try {
			InputStream is = IOUtils.getResourceAsStream(path, currentClass,
					false, false);

			if (is != null) {
				Properties props = new Properties();
				try {
					props.load(is);
					return props;
				} catch (IOException e) {
					logger
							.warn("Descriptor found but unable to load properties for service "
									+ name);
					return null;
				}
			} else {
				return null;
			}
		} catch (IOException e) {
			return null;
		}
	}
}
